package com.dx_society.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dx_society.domain.Activities;
import com.dx_society.domain.ActivityMember;
import com.dx_society.domain.Societies;
import com.dx_society.dto.*;
import com.dx_society.mapper.ActivityMemberMapper;
import com.dx_society.mapper.SocietiesMapper;
import com.dx_society.service.ActivitiesService;
import com.dx_society.mapper.ActivitiesMapper;
import com.dx_society.service.MessageService;
import com.dx_society.service.SocietiesService;
import com.dx_society.utils.QRCodeUtil;
import com.dx_society.utils.UserHolder;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.Collator;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.dx_society.utils.RedisConstants.*;

/**
 * @author 韶光善良君
 * @description 针对表【dx_activities(社团活动)】的数据库操作Service实现
 * @createDate 2024-07-01 10:14:20
 */
@Service
public class ActivitiesServiceImpl extends ServiceImpl<ActivitiesMapper, Activities>
        implements ActivitiesService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ActivityMemberMapper activityMemberMapper;
    @Resource
    private Snowflake snowflake;
    @Resource
    private SocietiesMapper societiesMapper;
    @Resource
    private MessageService messageService;
    @Override
    public Result queryActivitiesList(String acName, Long soId, Integer orderRole, Boolean isValid) {
        //1.从redis查询社团列表缓存
        List<String> listCache = stringRedisTemplate.opsForList().range(ACTIVITIES_LIST_KEY, 0, -1);
        //2.判断是否为空
        if (listCache != null && !listCache.isEmpty()) {
            //不为空，返回列表

            List<Activities> activitiesList = listCache.stream()
                    .map(str -> (Activities) JSONUtil.toBean(str, Activities.class, true))
                    .toList();
            if (isValid) {
                activitiesList = activitiesList.stream()
                        .filter(activity -> activity.getAcStarttime().after(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())))
                        .collect(Collectors.toList());
            }
            if (acName != null && !acName.isEmpty()) {
                activitiesList = activitiesList.stream()
                        .filter(societies -> societies.getAcName().contains(acName))
                        .collect(Collectors.toList());
            }
            if (soId != null && !soId.equals(0L)) {
                activitiesList = activitiesList.stream()
                        .filter(societies -> societies.getAcSocietyId().equals(soId))
                        .collect(Collectors.toList());
            }
            if (activitiesList.isEmpty()) {
                return Result.fail("没有找到符合条件的活动信息");
            }
            //排序方案 0默认排序 1参加人数降序 2时间升序 3综测分降序 4时间降序
            switch (orderRole) {
                case 0:
                    activitiesList = activitiesList.stream().sorted((l1, l2) -> {
                        Collator instance = Collator.getInstance(Locale.CHINA);
                        return instance.compare(l1.getAcName(), l2.getAcName());
                    }).toList();
                    break;
                case 1:
                    activitiesList = activitiesList.stream().sorted(Comparator.comparingLong(Activities::getAcCount).reversed()).toList();
                    break;
                case 2:
                    activitiesList = activitiesList.stream().sorted(Comparator.comparing(Activities::getAcStarttime)).toList();
                    break;
                case 3:
                    activitiesList = activitiesList.stream().sorted(Comparator.comparing(Activities::getAcScout).reversed()).toList();
                    break;
                case 4:
                    activitiesList = activitiesList.stream().sorted(Comparator.comparing(Activities::getAcStarttime).reversed()).toList();
                    break;
            }
            return Result.ok(activitiesList);
        }
        // 缓存不存在则重建缓存
        saveActivities2Redis(ACTIVITIES_LIST_TTL);
        return queryActivitiesList(acName, soId, orderRole, isValid);
    }

    @Override
    public void saveActivities2Redis(Long expireSeconds) {
        // 添加分布式锁
        RLock lock = redissonClient.getLock(CACHE_AC_LOCK_KEY);
        boolean isLock = lock.tryLock();
        if (isLock) {
            try {
                List<Activities> activitiesList = list();
                // 检查数据库缓存是否存在，存在则删除缓存
                if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(ACTIVITIES_LIST_KEY))) {
                    stringRedisTemplate.delete(ACTIVITIES_LIST_KEY);
                }
                // 将数据写入redis
                List<String> strList = activitiesList.stream().map(JSONUtil::toJsonStr).collect(Collectors.toList());
                stringRedisTemplate.opsForList().rightPushAll(ACTIVITIES_LIST_KEY, strList);
                stringRedisTemplate.expire(ACTIVITIES_LIST_KEY, expireSeconds, TimeUnit.MINUTES);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    }

    @Override
    public Result queryActivityDetail(Long id) {
        Long userId;
        try {
            userId = UserHolder.getUser().getUserid();
        } catch (Exception e) {
            return Result.fail("用户未登录");
        }
        //1.从redis查询社团列表缓存
        List<String> listCache = stringRedisTemplate.opsForList().range(ACTIVITIES_LIST_KEY, 0, -1);
        //2.判断是否为空
        if (listCache != null && !listCache.isEmpty()) {
            Activities activity = listCache.stream()
                    .map(str -> (Activities) JSONUtil.toBean(str, Activities.class, true))
                    .filter(activities -> activities.getAcId().equals(id))
                    .findFirst().orElse(null);
            if (activity == null) {
                return Result.fail("没有找到该活动信息");
            }
            AcDetailDTO acDetailDTO = new AcDetailDTO();
            acDetailDTO.setActivities(activity);

            QueryWrapper<ActivityMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("ac_id", id);
            queryWrapper.eq("user_id", userId);
            ActivityMember activityMember = activityMemberMapper.selectOne(queryWrapper);
            // 检查是否存在
            if (activityMember != null) {
                acDetailDTO.setIsMember(activityMember.getState());
            } else {
                // 不是该部部员
                acDetailDTO.setIsMember(-1);
            }
            return Result.ok(acDetailDTO);
        }
        // 缓存不存在则重建缓存
        saveActivities2Redis(ACTIVITIES_LIST_TTL);
        return queryActivityDetail(id);
    }

    @Value("${web.local-host}")
    private String host;
    @Value("${web.icon-path}")
    private String iconPath;

    @Override
    public Result createSignInfo(Long id) {
        Long userId;
        try {
            userId = UserHolder.getUser().getUserid();
        } catch (Exception e) {
            return Result.fail("用户未登录");
        }
        Activities ac = getById(id);
        if (ac == null) {
            return Result.fail("活动不存在");
        } else if (!Objects.equals(ac.getAcManagerId(), userId)) {
            return Result.fail("您不是该活动的管理员");
        } else {
            // 生成签到码
            String code = RandomUtil.randomNumbers(6);
            // 添加到redis
            stringRedisTemplate.opsForValue().set(AC_CODE_KEY + id, code, AC_CODE_TTL, TimeUnit.MINUTES);
            log.debug("生成签到码：" + code);

            // 签到二维码
            String text = "http://" + host + ":8083/ac/sign/" + id + "?sign=" + code;
            String filePath = "QR" + System.currentTimeMillis() + ".jpg";
            String destPath = "src/main/resources/static/QR/" + filePath;
            try {
                QRCodeUtil.encode(text, iconPath, destPath, true);
                String str = QRCodeUtil.decode(destPath);
                // 打印出解析出的内容
                System.out.println(str);
            } catch (Exception e) {
                log.debug("E:" + e);
            }
            String filePath1 = "http://" + host + ":8083/QR/" + filePath;
            AcSignCodeDTO acSignCodeDTO = new AcSignCodeDTO();
            acSignCodeDTO.setCode(code);
            acSignCodeDTO.setPath(filePath1);
            return Result.ok(acSignCodeDTO);
        }
    }

    @Override
    public Result pubActivity(AcMDTO acMDTO) {
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.fail("请先登录");
        } else if (user.getRole() != 1) {
            return Result.fail("权限不足");
        }
        QueryWrapper<Societies> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("so_master_id", user.getUserid());
        Societies soMasterId = societiesMapper.selectOne(queryWrapper);
        Long acId = snowflake.nextId();
        Activities ac = new Activities();
        ac.setAcId(acId);
        ac.setAcName(acMDTO.getAcName());
        ac.setAcAddress(acMDTO.getAcAddress());
        ac.setAcStarttime(acMDTO.getAcStarttime());
        ac.setAcEndtime(acMDTO.getAcEndtime());
        ac.setAcDetail(acMDTO.getAcDetail());
        ac.setAcScout(acMDTO.getAcScout());
        ac.setAcImage(acMDTO.getAcImage());
        ac.setAcManagerId(UserHolder.getUser().getUserid());
        ac.setAcSocietyId(soMasterId.getSoId());
        ac.setAcManagerName(UserHolder.getUser().getUsername());
        ac.setAcSocietyName(soMasterId.getSoName());

        String acJson = JSONUtil.toJsonStr(ac);
        stringRedisTemplate.opsForList().rightPush(AC_LIST_KEY, acJson);
        return Result.ok("活动发布成功，等待管理员审批");
    }

    @Override
    public Result queryUnpubAc() {
        List<String> listCache = stringRedisTemplate.opsForList().range(AC_LIST_KEY, 0, -1);
        if (listCache != null && !listCache.isEmpty()) {
            //不为空，返回列表

            List<Activities> activitiesList = listCache.stream()
                    .map(str -> (Activities) JSONUtil.toBean(str, Activities.class, true))
                    .toList();

            return Result.ok(activitiesList);

        } else {
            return Result.fail("没有待审批的活动");

        }
    }

    @Override
    public Result agreeActivity(Boolean agree, Long acId) {
        List<String> listCache = stringRedisTemplate.opsForList().range(AC_LIST_KEY, 0, -1);
        List<Activities> activitiesList = new ArrayList<>(listCache.stream()
                .map(str -> (Activities) JSONUtil.toBean(str, Activities.class, true))
                .toList());
        Activities activity = activitiesList.stream().filter(activities -> activities.getAcId().equals(acId))
                .findFirst().orElse(null);
        activitiesList.remove(activity);

        //AC_LIST_KEY缓存更新
        try {
            stringRedisTemplate.delete(AC_LIST_KEY);
            // 将剩余数据写入redis
            if (!activitiesList.isEmpty()) {
                List<String> strList = activitiesList.stream().map(JSONUtil::toJsonStr).collect(Collectors.toList());
                stringRedisTemplate.opsForList().rightPushAll(AC_LIST_KEY, strList);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        if (agree) {

            if (save(activity)) {
                messageService.sendMessage(activity.getAcManagerId(),"您的活动\""+activity.getAcName()+"\" 已过审");

                saveActivities2Redis(ACTIVITIES_LIST_TTL);
                return Result.ok("活动已通过");
            } else {
                return Result.ok("未知错误");
            }
        } else {
            messageService.sendMessage(activity.getAcManagerId(),"您的活动\""+activity.getAcName()+"\" 已拒绝");

            return Result.ok("已拒绝");
        }
    }

    @Override
    public Result queryMyUnpubList() {
        List<String> listCache = stringRedisTemplate.opsForList().range(AC_LIST_KEY, 0, -1);
        if (listCache != null && !listCache.isEmpty()) {
            List<Activities> acList = listCache.stream()
                    .map(str -> (Activities) JSONUtil.toBean(str, Activities.class, true))
                    .toList();
            return Result.ok(acList);
        } else {
            return Result.fail("没有待审核的活动");
        }
    }
}




